// This is just like the Gouraud.java program only the light is a spotlight.


	
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import javax.media.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.*;
import java.awt.*;
import javax.swing.*;

import java.awt.event.*;
import javax.swing.event.*;



public class Spot implements GLEventListener, ActionListener, ChangeListener {
	
	public static void main(String[] args) {
		new Spot();
	}
	
	private int INITIAL_WIDTH=800;
	private int INITIAL_HEIGHT=800;
	
	JButton quitButton, lightButton, materialButton;
	JLabel divisionsLabel;
	private GLCanvas canvas;
	private GL2 gl;
	private GLU glu;
	
	private JSlider lightXSlider, lightYSlider, lightZSlider, cutoffAngleSlider, divisionsSlider;
	
	private JFrame lightFrame, materialFrame;
	
	private boolean lightVisible =false;
	private boolean materialVisible = false;
		
	private float lightAmbient[] = {0f, 0f, 0f, 1f};
	private float lightDiffuse[] = {1f, 1f, 1f, 1f};
	private float lightSpecular[] = {1f, 1f, 1f, 1f};
	
	private float lightPosition[] = {5f, 0f, 5f, 1f};
	private float [ ] lightDirection = {-5f, 0f, -10f, 0f};
	
	private float cutoffAngle = 90;
	
	private float materialAmbient[] = {0.3f, 0f, 0f, 1f};
	private float materialDiffuse[] = {0.9f, 0f, 0f, 1f};
	private float materialSpecular[] = {0.9f, 0.9f, 0.9f, 1f};
	
	private int materialShininess = 32;
	
	private int divisions = 20;
	
	// The viewer is at (30, 0, 0); this doesn't change.
	private float viewerX = 30f;
	private float viewerY  = 0f;
	private float viewerZ = 0f;
	

	public  Spot() {
			GLProfile glp=GLProfile.getDefault();
			GLCapabilities caps = new GLCapabilities(glp);
			canvas = new GLCanvas(caps);
			JFrame frame = new JFrame("SPOT");

			frame.setSize(INITIAL_WIDTH, INITIAL_HEIGHT);
			frame.setLayout(new BorderLayout());
			JPanel north = new JPanel( new BorderLayout());
			
			JPanel firstMainRow = new JPanel( new FlowLayout(FlowLayout.LEADING));
			
			quitButton = new JButton( "Quit");
			quitButton.addActionListener(this);
			firstMainRow.add(quitButton);
			north.add(firstMainRow, BorderLayout.NORTH);
			
			JPanel secondMainRow = new JPanel( new FlowLayout(FlowLayout.LEADING));
			lightButton = new JButton( "Light Attributes");
			lightButton.addActionListener(this);
			secondMainRow.add(lightButton);
			materialButton = new JButton( "Material Attributes");
			materialButton.addActionListener(this);
			secondMainRow.add(materialButton);
			north.add(secondMainRow, BorderLayout.CENTER);
			
			lightFrame = new JFrame("Light Attributes");
			lightFrame.setSize(600, 300);
			lightFrame.setLayout(new GridLayout(4, 1));
			lightFrame.setVisible(false);	
			lightFrame.setAlwaysOnTop(true);
			lightFrame.setLocation(800, 50);

			JPanel row1 = new JPanel(new BorderLayout());
			lightXSlider = newSlider(row1, -100, 100, 25, "Position X");
			lightXSlider.setValue( (int)(lightPosition[0]));
			lightFrame.add(row1);
			JPanel row2 = new JPanel(new BorderLayout());
			lightYSlider = newSlider(row2, -100, 100, 25, "Position Y");
			lightYSlider.setValue( (int)(lightPosition[1]));
			lightFrame.add(row2);
			JPanel row3 = new JPanel(new BorderLayout());
			lightZSlider = newSlider(row3, -100, 100, 25, "Position Z");
			lightZSlider.setValue( (int)(lightPosition[2]));
			lightFrame.add(row3);
			JPanel row4 = new JPanel(new BorderLayout());
			cutoffAngleSlider = newSlider(row4, 0, 90, 10, "Cutoff Angle");
			cutoffAngleSlider.setValue( (int)cutoffAngle );
			lightFrame.add(row4);

			materialFrame = new JFrame("Material Properties");
			materialFrame.setSize(600, 300);
			materialFrame.setLayout(new GridLayout(3, 1));
			materialFrame.setVisible(false);	
			materialFrame.setAlwaysOnTop(true);
			materialFrame.setLocation(800, 50);
			
			JPanel row5 = new JPanel(new BorderLayout());
			divisionsSlider = newSlider(row5, 1, 100, 10, " Square Divisions");
			Float [] L = new Float[1];
			L[0] = new Float(divisions);
			divisionsLabel = new JLabel(String.format( "%5.0f     ", L));
			row5.add(divisionsLabel, BorderLayout.EAST);
			divisionsSlider.setValue( divisions );
			
			materialFrame.add(row5);

			frame.add(north, BorderLayout.NORTH);
			JPanel myCanvas = new JPanel(new GridLayout(1,1));
			myCanvas.add(canvas);
			frame.add(myCanvas, BorderLayout.CENTER);
			
			frame.setVisible(true);
			canvas.addGLEventListener(this);

			FPSAnimator animator = new FPSAnimator(canvas, 60);
			animator.start(); 
			
	}
	
	// This assumes the parent is a panel using BorderLayout.
	JSlider newSlider(JPanel parent, int min, int max, int step, String label) {
		JSlider S = new JSlider(min, max);
		S.setMajorTickSpacing(step);
		S.setPaintTicks(true);
		S.setPaintLabels(true); 
		S.addChangeListener(this);
		JLabel name = new JLabel(label);
		parent.add(name, BorderLayout.WEST); 
		parent.add(S, BorderLayout.CENTER);
		return S;
	}
	
	public void actionPerformed(ActionEvent event) {
			if (event.getSource() == quitButton)
				System.exit(0);
			else if (event.getSource() == lightButton) {
				lightVisible = !lightVisible;
				lightFrame.setVisible(lightVisible);
			}
			else if (event.getSource() == materialButton) {
				materialVisible = !materialVisible;
				materialFrame.setVisible(materialVisible);
			}
	}
	
	public void stateChanged(ChangeEvent e) {
		if (e.getSource() == lightXSlider) {
			lightPosition[0] = lightXSlider.getValue();
			lightDirection[0] = -lightPosition[0];
		}
		else if (e.getSource() == lightYSlider) {
			lightPosition[1] = lightYSlider.getValue();
			lightDirection[1] = -lightPosition[1];
		}
		else if (e.getSource() == lightZSlider) {
			lightPosition[2] = lightZSlider.getValue();
			lightDirection[2] = -lightPosition[2];
		}
		else if (e.getSource() == cutoffAngleSlider) {
			cutoffAngle = cutoffAngleSlider.getValue();
		}
		else if (e.getSource() == divisionsSlider) {
			divisions = divisionsSlider.getValue();
			Float [] L = new Float[1];
			L[0] = new Float(divisions);
			divisionsLabel.setText(String.format( "%5.0f     ", L));
		}
	}

	public void display(GLAutoDrawable drawable) {
		update();
		render(drawable);
	}

	private void update() {	
	}

	
	private void render(GLAutoDrawable drawable) {
		
		gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
		
		gl.glLightfv(GL2.GL_LIGHT1,  GL2.GL_POSITION, lightPosition, 0);
		gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPOT_DIRECTION, lightDirection, 0);
		gl.glLightf(GL2.GL_LIGHT1, GL2.GL_SPOT_CUTOFF, cutoffAngle);
		gl.glLightf(GL2.GL_LIGHT1, GL2.GL_SPOT_EXPONENT, 5);


		gl.glPushMatrix();
		square( divisions );
		gl.glPopMatrix();

	}
	
	// This makes a square that is 20 units on each side;
	// it is divided into divisionsxdivisions subsquares
	private void square(int divisions) {
		float left = -10f;
		float right = 10f;
		float top = -10f;
		float bottom = 10f;
		float delta = 20f/divisions;
		
		gl.glNormal3f(1f, 0f, 0f);
		for (float y = left; y+delta/2 < right; y += delta) {
			for (float z = top; z+delta/2 < bottom; z += delta) {
				gl.glBegin(GL2.GL_POLYGON);
				gl.glVertex3f(0f, y, z);
				gl.glVertex3f(0f, y+delta, z);
				gl.glVertex3f(0f,  y+delta, z+delta);
				gl.glVertex3f(0f, y, z+delta);
				gl.glEnd();
			}
		}
	}

	public void dispose(GLAutoDrawable drawable) {
		// put the cleanup code here
		
	}

	public void init(GLAutoDrawable drawable) {		
		gl = drawable.getGL().getGL2();
		glu = new GLU();
		

		gl.glEnable(GL2.GL_DEPTH_TEST);
		
		gl.glShadeModel(GL2.GL_SMOOTH);

		gl.glMatrixMode(GL2.GL_PROJECTION);
		gl.glLoadIdentity();
		glu.gluPerspective(60f, 1f, 0.5f, 200f); 
		gl.glMatrixMode(GL2.GL_MODELVIEW);
		gl.glLoadIdentity();
		glu.gluLookAt(viewerX, viewerY, viewerZ, 0f, 0f, 0f, 0f, 0f, 1f);

		gl.glEnable(GL2.GL_LIGHTING);
		gl.glEnable(GL2.GL_LIGHT1);
		gl.glLightfv(GL2.GL_LIGHT1,  GL2.GL_AMBIENT, lightAmbient, 0);
		gl.glLightfv(GL2.GL_LIGHT1,  GL2.GL_DIFFUSE, lightDiffuse, 0);
		gl.glLightfv(GL2.GL_LIGHT1,  GL2.GL_SPECULAR, lightSpecular, 0);
		gl.glLightfv(GL2.GL_LIGHT1,  GL2.GL_POSITION, lightPosition, 0);
		gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPOT_DIRECTION, lightDirection, 0);
		gl.glLightf(GL2.GL_LIGHT1, GL2.GL_SPOT_CUTOFF, cutoffAngle);

		gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, materialAmbient, 0);
		gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, materialDiffuse, 0);
		gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, materialSpecular, 0);
		gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, materialShininess);

		gl.glMatrixMode(GL2.GL_PROJECTION);
		gl.glLoadIdentity();
		glu.gluPerspective(60f, 1f, 0.5f, 200f); 
		gl.glMatrixMode(GL2.GL_MODELVIEW);
		gl.glLoadIdentity();
		glu.gluLookAt(viewerX, viewerY, viewerZ, 0f, 0f, 0f, 0f, 0f, 1f);
		gl.glClearColor(1f, 1f, 1f, 1f);
		gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
	}

	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		// this is called when the window is resized
		gl.glViewport(0, 0, width, height);
		float aspect = width*1.0f/height;
		gl.glMatrixMode(GL2.GL_PROJECTION);
		gl.glLoadIdentity();
		glu.gluPerspective(60f, aspect, 0.5f, 200f); 
		gl.glMatrixMode(GL2.GL_MODELVIEW);
		
		
	}
	
}
